package com.binarysoft.cmdhandler.common.thread;

import java.util.StringTokenizer;

import common.framework.command.handler.AbstractCommandHandler;
import common.framework.command.helper.CommandHelper;
import common.framework.command.server.Terminal;
import common.framework.dsb.annotation.DSBCmd;

@DSBCmd("thread")
public class ShowThreadCmdHandler extends AbstractCommandHandler {

	public void close() {

	}

	public void handle(String args, Terminal terminal) throws Exception {
		terminal.println("");
		StringTokenizer stier = new StringTokenizer(args);
		int count = stier.countTokens();
		if (count < 2) {
			terminal.println(" Usage:");
			terminal.println(" thread ls               -- list all threads");
			terminal.println(" thread ls <Thread ID>   -- list specified thread with given <thread ID>");
			terminal.println("");
			return;
		}
		stier.nextToken();
		String cmd = stier.nextToken();

		if ("ls".equalsIgnoreCase(cmd) && count == 2) {
			listThread(terminal);
		} else if ("ls".equalsIgnoreCase(cmd) && count == 3) {
			String sID = stier.nextToken();
			int threadID = 0;
			try {
				threadID = Integer.parseInt(sID);
			} catch (NumberFormatException e) {
				terminal.println(" Thread ID should be a number!");
				terminal.println("");
				return;
			}
			listThread(terminal, threadID);
		} else {
			terminal.println(" Usage:");
			terminal.println(" thread ls            -- list all threads");
			terminal.println(" thread <Thread ID>   -- list specified thread with given <thread ID>");
		}
		terminal.println("");
	}

	private void listThread(Terminal terminal) throws Exception {
		ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
		ThreadGroup rootGroup = getRootThreadGroup(threadGroup);
		Thread[] threads = new Thread[rootGroup.activeCount()];
		rootGroup.enumerate(threads);
		String[] tableHAD = { "ID", "Priority", "State", "Name" };
		String[] tableGAP = { "--", "--------", "-----", "----" };
		int[] format = { 6, 10, 15, 30 };
		terminal.println(CommandHelper.format(tableHAD, format));
		terminal.println(CommandHelper.format(tableGAP, format));
		for (int i = 0; i < threads.length; i++) {
			Thread th = threads[i];
			Object[] row = { th.getId(), th.getPriority(), th.getState(), th.getName() };
			terminal.println(CommandHelper.format(row, format));
		}
		terminal.println("");
		terminal.println(" Total " + threads.length + " thread(s).");
	}

	private void listThread(Terminal terminal, int threadID) throws Exception {
		ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
		ThreadGroup rootGroup = getRootThreadGroup(threadGroup);
		Thread[] threads = new Thread[rootGroup.activeCount()];
		rootGroup.enumerate(threads);
		String[] tableHAD = { "ID", "Priority", "State", "Name" };
		String[] tableGAP = { "--", "--------", "-----", "----" };
		int[] format = { 6, 10, 15, 30 };
		terminal.println(CommandHelper.format(tableHAD, format));
		terminal.println(CommandHelper.format(tableGAP, format));
		for (int i = 0; i < threads.length; i++) {
			Thread th = threads[i];
			if (th.getId() == threadID) {
				Object[] row = { th.getId(), th.getPriority(), th.getState(), th.getName() };
				terminal.println(CommandHelper.format(row, format));
				terminal.println("");
				terminal.println("Stack trace:");
				StackTraceElement[] stackTraces = th.getStackTrace();
				for (int j = 0; j < stackTraces.length; j++) {
					StackTraceElement ste = stackTraces[j];
					terminal.println("  at " + ste.toString());
				}
			}
		}
	}

	private ThreadGroup getRootThreadGroup(ThreadGroup current) {
		ThreadGroup parent = current.getParent();
		if (parent == null) {
			return current;
		} else {
			return getRootThreadGroup(parent);
		}
	}

}
